<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Empty page</title>
<style>
@-moz-document url-prefix() {
  button {
    padding: 0px;
  }
}

.noselect-txt {
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}

html {
  width: 100%;
  height: 100%;
  -ms-overflow-style: -ms-autohiding-scrollbar;
}
body {
  width: 98%;
  height: 100%;
  background-color: #e8e8e8;
  margin: 2px;
  font-size: 14px;
  color: #222;
  line-height: 1.6;
}

.tool-btn, .tool-img {
  padding: 0px;
  border: 1px solid transparent;
  width: 16px;
  height: 16px;
}
.tool-btn:hover {
  border-color: #fff #aaa #aaa #fff;
}

#file-list td, #file-list th {
  padding: 0px;
  cursor: default;
}

.thumb-item {
  width: 90px;
  margin: 2px;
}
.thumb-item:hover {
  outline: 1px dotted red;
}
</style>
</head>

<body>

<div style='width:100%; height:100%; overflow-x:hidden; overflow-y:auto'>
<table id='file-list' class='noselect-txt' style='width:100%; margin:0px; padding:0px; border:0px; border-spacing:0px; border-collapse:collapse; table-layout:auto; line-height:0.9'>
  <tr id='filelist-title'>
    <th style='width:20px'><img class='tool-btn' title='refresh' src='res/refresh.png'></th>
    <th style='text-align:left'>
      <div style='display:inline-block; width:54px; height:18px; overflow:hidden'><img class='tool-btn' title='current directory' style='display:none' src='res/home_page.png'><img class='tool-btn' style='display:none' src='res/upload.png'><input type='file' title='upload file' style='display:none; position:relative; left:-18px; top:-6px; width:18px; height:22px; opacity:0' multiple /></div>
      <span style='position:relative; left:6px; top:1px; vertical-align:super'></span>
    </th>
  </tr>
  <tr id='goto-uplevel'>
    <td><img class='tool-img' src='res/file_up.png'></td><td>..</td>
  </tr>
</table>

<div id='widget-list' style='width:100%; background-color:#fff; border-radius:3px; margin:6px 0px; text-align:center'>
</div>

</div>

<div id='preview-img' style='display:none; position:absolute; background-color:#fff; left:80px; top:40px; width:130px; outline:1px solid #ccc'>
  <img draggable='true' style='width:100%'>
</div>

<div id='open-md' style='display:none; position:absolute; top:0px; right:8px'>
  <button>view</button>
</div>
<div id='rmv-file' style='display:none; position:absolute; top:0px; right:20px'>
  <button>remove</button>
</div>
<div id='new-folder' style='display:none; position:absolute; top:0px; right:8px'>
  <button>new folder</button>
</div>

<script src='js/shadow-gits.min.js'></script>
<script src='js/pseudo_w.js'></script>
<script>
if (!Array.prototype.findIndex) {  // polyfill function
  Array.prototype.findIndex = function(predicate) {
    // 1. Let O be ? ToObject(this value).
    if (this == null) {
      throw new TypeError('"this" is null or not defined');
    }

    var o = Object(this);

    // 2. Let len be ? ToLength(? Get(O, "length")).
    var len = o.length >>> 0;

    // 3. If IsCallable(predicate) is false, throw a TypeError exception.
    if (typeof predicate !== 'function') {
      throw new TypeError('predicate must be a function');
    }

    // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
    var thisArg = arguments[1];

    // 5. Let k be 0.
    var k = 0;

    // 6. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ! ToString(k).
      // b. Let kValue be ? Get(O, Pk).
      // c. Let testResult be ToBoolean.
      // d. If testResult is true, return k.
      var kValue = o[k];
      if (predicate.call(thisArg, kValue, k, o)) {
        return k;
      }
      // e. Increase k by 1.
      k++;
    }

    // 7. Return -1.
    return -1;
  };
}

if (!Array.prototype.find) {  // polyfill function
  var fn_array_find_ = Array.prototype.findIndex;
  Array.prototype.find = function() {
    // 1. Let O be ? ToObject(this value).
    if (this == null) {
      throw new TypeError('"this" is null or not defined');
    }

    var o = Object(this);
    var i = fn_array_find_.apply(o,arguments);
    return i >= 0? o[i]: undefined;
  };
}

(function() {

var fileTBodyNode  = null;
var titleTdNode    = null;
var uplevelTrNode  = null;
var widgetListNode = null;
var previewImgNode = null;
var removFileNode  = null;
var viewMdFileNode = null;
var newFolderNode  = null;
var homeImgNode    = null;
var uploadImgNode  = null;
var uploadFileNode = null;
var titleSpanNode  = null;

var proxyDirList   = false;
var canShowHomeBtn = false;
var canShowUpldBtn = false;

var inputJson    = null;
var hasProjBase  = false;
var sWorkDirUrl  = '';
var sWorkDirBase = '';
var sWorkDirHome = '';
var sLastListUrl = '';

var Git = null, userObj = null, braObj = null;
var utils = window.W? W.$utils: null;

var canUpload = !!(window.File && window.FileList && window.FileReader);
var Uploads = {uploading:[], checkTid:0, cache:{}};

function joinPath(s1,s2) {
  if (!s2) return s1;
  if (!s1) return s2;
  
  if (s2[0] == '/') {
    if (s1.slice(-1) == '/')
      return s1 + s2.slice(1);
    else return s1 + s2;
  }
  else {
    if (s1.slice(-1) == '/')
      return s1 + s2;
    else return s1 + '/' + s2;
  }
}

function setUploadHint(iCount) {
  uploadFileNode.setAttribute('title','uploading ' + iCount + ' file(s)');
}

var dMeta_ = {
  txt:  {meta:"text/plain", icon:"res/file_txt.png"},
  md:   {meta:"text/x-markdown", icon:"res/file_md.png"},
  html: {meta:"text/html", icon:"res/file_html.png"},
  htm:  {meta:"text/html", icon:"res/file_html.png"},
  jpg:  {meta:"image/jpeg", icon:"res/file_img.png"},
  jpeg: {meta:"image/jpeg", icon:"res/file_img.png"},
  gif:  {meta:"image/gif", icon:"res/file_img.png"},
  png:  {meta:"image/png", icon:"res/file_img.png"},
  ico:  {meta:"image/x-icon", icon:"res/file_img.png"},
  svg:  {meta:"image/svg+xml", icon:"res/file_img.png"},
  wav:  {meta:"audio/x-wav", icon:"res/file_audio.png"},
  mp3:  {meta:"audio/mpeg", icon:"res/file_audio.png"},
  mpeg: {meta:"video/mpeg", icon:"res/file_video.png"},
  avi:  {meta:"video/x-msvideo", icon:"res/file_video.png"},
  mp4:  {meta:"video/mp4", icon:"res/file_video.png"},
  mov:  {meta:"video/quicktime", icon:"res/file_video.png"},
  js:   {meta:"application/javascript", icon:"res/file_js.png"},
  css:  {meta:"text/css", icon:"res/file_css.png"},
  xml:  {meta:"text/xml", icon:"res/file_xml.png"},
  rtf:  {meta:"application/rtf", icon:"res/file_rtf.png"},
  zip:  {meta:"application/zip", icon:"res/file_zip.png"},
  tar:  {meta:"application/x-tar", icon:"res/file_zip.png"}
};
var unknownMeta_ = {meta:'application/octet-stream', icon:'res/file_other.png'};

var dMeta2_ = {};
Object.keys(dMeta_).forEach( function(sKey) {
  var item = dMeta_[sKey];
  dMeta2_[item.meta] = item.icon;
});

function metaIconUrl(sType) {
  return dMeta2_[sType] || unknownMeta_.icon;
}

function rmvExpiredCache() {
  var imgCache = Uploads.cache, b = Object.keys(imgCache);
  var fNow = (new Date()).valueOf();
  b.forEach( function(sKey) {
    var item = imgCache[sKey];
    if (fNow - item.startTm > 600000)  // 10 minutes = 10 * 60 * 1000
      delete imgCache[sKey];
  });
}

Uploads.upload = function(sPath,f) { // f.name, f.size, f.lastModified, f.type
  var loadTask = {path:sPath, name:f.name, startTm:(new Date()).valueOf(), type:f.type};
  var iCount = Uploads.uploading.push(loadTask);
  if (iCount == 1)
    uploadImgNode.setAttribute('src','res/loading.gif');
  setUploadHint(iCount);
  
  var reader = new FileReader();
  reader.onload = function(event) {
    var sInput = reader.result.replace(/^data:[^;]+;base64,/,'');
    uploadGitFile(sInput);
  };
  reader.readAsDataURL(f);  // readAsText readAsDataURL, readAsBinaryString, readAsArrayBuffer
  
  function uploadGitFile(sInput) {
    var b = loadTask.path.split('/');
    b.pop();
    var dirObj = braObj.dirOf(b.join('/'));
    dirObj.newFile(loadTask.name,undefined, function(err,bOut) {
      if (err) {
        console.log(err);
        onUploadDone(null);
      }
      else onUploadDone(bOut[0])  // bOut[0] is fileObj
    },sInput);
  }
  
  function onUploadDone(fileObj) {
    var iPos = Uploads.uploading.indexOf(loadTask);
    if (iPos >= 0) {
      Uploads.uploading.splice(iPos,1);
      var iCount = Uploads.uploading.length;
      if (iCount) setUploadHint(iCount);
    }
    
    if (fileObj) {  // success
      var sType = loadTask.type;
      if (sType.indexOf('image') == 0) {
        rmvExpiredCache();
        Uploads.cache[loadTask.path] = { name:loadTask.name, type:sType,
          startTm: (new Date()).valueOf(),
          data: 'data:' + loadTask.type + ';base64,' + fileObj.content,
        };
      }
      addFileNode(loadTask,metaIconUrl(sType));
    }
  }
  
  function addFileNode(loadTask,iconUrl) {
    var tr = document.createElement('tr');
    
    var td = document.createElement('td');
    var img = document.createElement('img');
    img.setAttribute('class','tool-img');
    img.setAttribute('src',iconUrl);
    img.setAttribute('draggable','true');
    img.ondragstart = fileDragStart;
    img.ondragend = fileDragEnd;
    td.appendChild(img);
    tr.appendChild(td);
    
    var td2 = document.createElement('td');
    td2.innerHTML = htmlEncode(loadTask.name);
    tr.appendChild(td2);
    
    tr.setAttribute('data-name',loadTask.name);
    tr.setAttribute('data-type',loadTask.type);
    tr.addEventListener('click',fileOnClick,false);
    fileTBodyNode.appendChild(tr);
  }
};

Uploads.remove = function(sPath,sSha) {
  var fileObj = braObj.fileOf(sPath);
  if (!braObj.isLocal && sSha) fileObj.sha = sSha;
  
  fileObj.remove( function(err,bOut) {
    if (err) {
      console.log(err);
      onRemoveDone(false);
    }
    else onRemoveDone(true);
  });
  
  function onRemoveDone(succ) {
    if (!succ) {
      alert('remove file (' + sPath + ') failed');
      return;
    }
    
    // find file node and remove it
    var b = sPath.split('/'), sName = b.pop(), sHead = '/' + braObj.repoName + '/' + b.join('/');
    if (sHead !== inputJson.path) return;  // ignore when not in same folder
    
    var nodes = fileTBodyNode.querySelectorAll('tr[data-name]');
    for (var i=0,node; node=nodes[i]; i++) {
      if (node.getAttribute('data-name') === sName) {
        node.parentNode.removeChild(node);
        break;
      }
    }
  }
};

//------
function getCacheImg(sPath) {
  if (!braObj || sPath.indexOf('/'+braObj.repoName+'/') != 0) return '';
  var sPath2 = sPath.slice(braObj.repoName.length+2);
  
  rmvExpiredCache();
  var item = Uploads.cache[sPath2];
  return item && item.data;
}

function listGitFiles(sUrl,callback) {
  var sPath, sHead = '/' + braObj.repoName;
  if (sUrl == sHead)
    sPath = '';
  else if (sUrl.indexOf(sHead + '/') == 0)
    sPath = sUrl.slice(sHead.length+1);
  else {
    console.log('invalid project base:',sUrl);
    return callback('invalid path');
  }
  
  braObj.dirOf(sPath).fetchContents( function(err,dirObj) {
    if (err) {
      console.log(err);
      return callback('request failed');
    }
    
    var bFolder = [], bFile = [], bTemplate = [];
    dirObj.contents.forEach( function(item) {
      var sName = item.name;
      if (item.type == 'file') {   // path,name,size,  ctime,mtime
        var d, bExt = sName.split('.'), sExt = bExt.length >= 2? bExt.pop(): '', isJsonSvg = false;
        if (sExt) {
          sExt = sExt.toLowerCase();
          if (sExt == 'svg' && bExt.length >= 2 && bExt.pop() == 'json')
            isJsonSvg = true;
          d = dMeta_[sExt] || unknownMeta_;
        }
        else d = unknownMeta_;
        
        if (isJsonSvg) {
          bTemplate.push(sName);
          return;
        }
        else if (d.meta.indexOf('image/') == 0) {
          var ss = sName + '.json';
          var iPos = dirObj.contents.findIndex( function(item2) {
            return item2.type == 'file' && item2.name == ss;
          });
          if (iPos >= 0) {
            bTemplate.push(sName);
            return;
          }
        }
        bFile.push([sName,d.meta,d.icon,item.sha]);  // item.sha maybe undefined
      }
      else { // item.type == 'dir' // path,name,size
        bFolder.push(sName);
      }
    });
    bTemplate.forEach( function(item) { // remove template.png.json from bFile
      var iPos = bFile.findIndex( function(item2) { return item2[0] === item+'.json'; } );
      if (iPos >= 0) bFile.splice(iPos,1);
    });
    
    bFolder.sort();
    bFile.sort(function(a,b) { return a[0] > b[0]? 1: (a[0] == b[0]? 0: -1); });
    bTemplate.sort();
    
    inputJson = { title:sPath.split('/').pop(), atTop:!sPath,
      path: sPath?sHead+'/'+sPath:sHead,
      folders:bFolder, files:bFile, templates:bTemplate,
    };
    callback('');  // success
  });
}

function uploadOnSelect(event) {
  if (!braObj) return;
  if (!canUpload) return; // no window.FileReader
  
  var files = event.target.files;
  if (!files.length) return;
  
  var sHeadSeg = '/' + braObj.repoName + '/';
  if (sLastListUrl.indexOf(sHeadSeg) != 0) {
    alert('Invalid folder to upload');
    return;
  }
  var pathOfRepo = sLastListUrl.slice(sHeadSeg.length); // first char is not '/'
  
  var sUpErr = '', iNum = 0;
  for (var i=0,file; file=files[i]; i++) {
    var sPath = joinPath(pathOfRepo,file.name);
    var iPos = Uploads.uploading.findIndex( function(item) {
      return item.path == sPath;
    });
    if (iPos >= 0) {
      sUpErr = 'file already in loading: ' + file.name;
      console.log(sUpErr);
    }
    else {
      if (file.size > 0xA00000) { // > 10M
        sUpErr = 'upload file (' + file.name + ') should less than 10M';
        console.log(sUpErr);
      }
      else if (currExistFile(file.name)) {
        sUpErr = 'file or directory already exist: ' + file.name;
        console.log(sUpErr);
      }
      else {
        iNum += 1;
        Uploads.upload(sPath,file);
      }
    }
  }
  
  if (sUpErr && iNum == 0) alert(sUpErr);
  
  if (iNum && !Uploads.checkTid) {
    Uploads.checkTid = setInterval( function() {  // checking task: try remove timeout item
      if (!Uploads.uploading.length) {
        clearInterval(Uploads.checkTid);
        Uploads.checkTid = 0;
        uploadImgNode.setAttribute('src','res/upload.png');
        uploadFileNode.setAttribute('title','upload file');
        return;
      }
      
      var changed = false, fNow = (new Date()).valueOf();
      for (var i=0,item; item=Uploads.uploading[i]; i++) {
        if (fNow - item.startTm >= 600000) { // 10 minutes = 10*60*1000
          changed = true;
          Uploads.uploading.splice(i,1);
          i -= 1;    // continue at same position
        }
      }
      if (changed) {
        var iCount = Uploads.uploading.length;
        if (iCount) setUploadHint(iCount);
      }
    },1500);
  }
  
  function currExistFile(sName) {
    var node = null;
    try {
      node = fileTBodyNode.querySelector('tr[data-name="' + sName + '"]');
    }
    catch(e) { }
    return !!node;
  }
}

function removeFileClick(event) {
  var targ = event.target;
  if (!targ || targ.parentNode !== removFileNode) return;
  
  var sPath = removFileNode.getAttribute('rmvsrc') || '';
  if (!canShowUpldBtn || !braObj || !sPath) return;
  
  event.stopPropagation();
  if (!window.confirm('do you want remove file: ' + sPath)) return;
  
  hideAllFloatBtn();
  var sSha = removFileNode.getAttribute('data-sha') || '';
  Uploads.remove(sPath,sSha);
}

function tryCreateFolder(sName) {
  var sName = window.prompt('input folder name');
  if (sName) sName = sName.trim();
  if (!sName || !braObj) return;
  
  sName = sName.replace(/[\\|:*?<>"]+/g,'');  // "
  sName = sName.split('/')[0];
  if (!sName) return;
  
  var owner = uplevelTrNode.parentNode, tr = newOneFolder(sName);
  var sibling = uplevelTrNode.nextElementSibling;
  if (!sibling)
    owner.appendChild(tr);
  else owner.insertBefore(tr,sibling);
}

//------
function htmlEncode(s) {
  return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}

function getUrlParam(s) {
  var dRet = {}, b = s.split('&');
  b.forEach( function(item) {
    if (!item) return;
    var b2 = item.split('='), sName = b2[0].trim();
    if (sName)
      dRet[sName] = (b2[1] || '').trim();
  });
  return dRet;
}

function location__(href) {
  var location = document.createElement('a');
  location.href = href;
  if (location.host == '')
    location.href = location.href;
  return location;
}

function getAsynRequest(sUrl,callback) {  // callbac must passed
  var xmlHttp = null;
  if (window.XMLHttpRequest)      // Firefox, Opera, IE7, etc
    xmlHttp = new XMLHttpRequest();
  else if (window.ActiveXObject)  // IE6, IE5
    xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
  
  if (xmlHttp) {
    xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState == 4) { // 4 is "loaded"
        if (xmlHttp.status == 200)   // success save
          callback(null,xmlHttp.responseText);
        else callback(new Error('XMLHttpRequest failed'));
        xmlHttp = null;
      }
    };
    xmlHttp.open('GET',sUrl,true);
    xmlHttp.send(null);
  }
}

function newOneFolder(sName) {
  var tr = document.createElement('tr');
  var td = document.createElement('td');
  var img = document.createElement('img');
  img.setAttribute('class','tool-img');
  img.setAttribute('src','res/file_folder.png');
  td.appendChild(img);
  tr.appendChild(td);
  
  var td2 = document.createElement('td');
  td2.innerHTML = htmlEncode(sName);
  tr.appendChild(td2);
  
  tr.setAttribute('data-name',sName);
  tr.addEventListener('dblclick',sublevelOnDbClick,false);
  return tr;
}

function hideAllFloatBtn(event) {
  if (removFileNode) removFileNode.style.display = 'none';
  if (previewImgNode) previewImgNode.style.display = 'none';
  if (viewMdFileNode) viewMdFileNode.style.display = 'none';
  if (newFolderNode) newFolderNode.style.display = 'none';
}

function updateInputJson(sUrl,callback) {  // callback must passed
  if (braObj) {
    listGitFiles(sUrl,whenGetJson);
  }
  else {
    var sUrl2 = sWorkDirUrl + '?base=' + encodeURIComponent(sWorkDirBase) + '&url=' + encodeURIComponent(sUrl);
    getAsynRequest(sUrl2, function(err,sJson) {
      var sErr = '';
      if (err) {
        sErr = 'Request failed';
        console.log('request failed: ' + sUrl);
        console.log(err);
      }
      else {
        try {
          inputJson = JSON.parse(sJson);
        }
        catch(e) {
          sErr = 'Invalid JSON';
          console.log('parse JSON failed: ' + e);
        }
      }
      whenGetJson(sErr);
    });
  }
  
  function whenGetJson(sErr) {
    // reset GUI
    titleSpanNode.innerHTML = '';
    uplevelTrNode.style.display = 'none';
    while (fileTBodyNode.children.length >= 3) {
      fileTBodyNode.removeChild(fileTBodyNode.children[2]);
    }
    widgetListNode.innerHTML = '';
    hideAllFloatBtn();
    
    // update content
    if (sErr) {
      titleSpanNode.innerHTML = sErr;
      callback(false);
    }
    else {
      setupByJson();
      callback(true);
    }
  }
  
  function setupByJson() {
    if (!inputJson) return;
    
    // step 1: setup title, uplevel
    var showGoHome = canShowHomeBtn && sWorkDirUrl;
    homeImgNode.style.display = showGoHome? 'inline': 'none';
    uploadFileNode.style.display = uploadImgNode.style.display = (canShowUpldBtn? 'inline': 'none');
    
    titleSpanNode.innerHTML = htmlEncode(inputJson.title || '');
    titleSpanNode.setAttribute('title',inputJson.path); // inputJson.path must be string
    uplevelTrNode.style.display = inputJson.atTop? 'none': 'table-row';
    
    // step 2: setup folders
    (inputJson.folders || []).forEach( function(item) {
      fileTBodyNode.appendChild(newOneFolder(item));
    });
    
    // step 3: setup files
    (inputJson.files || []).forEach( function(item) {
      var sName = item[0], sMeta = item[1], sUrl = item[2], sSha = item[3];
      var tr = document.createElement('tr');
      
      var td = document.createElement('td');
      var img = document.createElement('img');
      img.setAttribute('class','tool-img');
      img.setAttribute('src',sUrl);
      img.setAttribute('draggable','true');
      img.ondragstart = fileDragStart;
      img.ondragend = fileDragEnd;
      td.appendChild(img);
      tr.appendChild(td);
      
      var td2 = document.createElement('td');
      td2.innerHTML = htmlEncode(sName);
      tr.appendChild(td2);
      
      tr.setAttribute('data-name',sName);
      tr.setAttribute('data-type',sMeta);
      if (sSha) tr.setAttribute('data-sha',sSha);
      tr.addEventListener('click',fileOnClick,false);
      fileTBodyNode.appendChild(tr);
    });
    
    // step 4: setup templates
    (inputJson.templates || []).forEach( function(item) {
      var sTitle, jsonSvg = item.slice(-9) == '.json.svg';
      var img, sUrl = inputJson.path? inputJson.path + '/' + item: item;
      if (jsonSvg) {
        sTitle = item.slice(0,-9);
        img = document.createElement('div');
        var objNode = document.createElement('object');
        objNode.onload = function(event) {
          var gNode = objNode.contentDocument.querySelector('g');
          if (gNode) {
            var sJson = gNode.getAttribute('_widget') || '';
            if (sJson && sJson[0] == '{' && sJson.slice(-1) == '}') {
              gNode.removeAttribute('_widget');
              try {
                img.wdgtJson = JSON.parse(sJson);
              }
              catch(e) { console.log(e); }
            }
          }
        };
        objNode.setAttribute('data',sUrl);
        objNode.setAttribute('type','image/svg+xml');
        objNode.setAttribute('style','width:100%; pointer-events:none;');
        img.setAttribute('data-src',sUrl);
        img.setAttribute('style','display:inline-block; line-height:0;');
        img.appendChild(objNode);
      }
      else {
        var b = item.split('.');
        b.pop();
        sTitle = b.join('.');
        img = document.createElement('img');
        img.setAttribute('src',sUrl);
      }
      img.setAttribute('title',sTitle);
      img.setAttribute('class','thumb-item');
      img.setAttribute('draggable','true');
      img.ondragstart = thumbDragStart;
      img.ondragend = thumbDragEnd;
      widgetListNode.appendChild(img);
    });
  }
}

function refreshOnClick(event) {
  event.stopPropagation();  
  if (sWorkDirUrl && sLastListUrl) {
    updateInputJson(sLastListUrl, function(succ) {
      // sLastListUrl not changed
    });
  }
}

function goHomeOnClick(event) {
  event.stopPropagation();  
  if (hasProjBase && sWorkDirUrl) {
    updateInputJson(sWorkDirHome, function(succ) {
      if (succ) sLastListUrl = sWorkDirHome;
    });
  }
}

function uplevelOnDbClick(event) {
  event.stopPropagation();
  if (!inputJson || inputJson.atTop) return;
  
  if (sWorkDirUrl && sLastListUrl) {
    var sNewUrl, s = sLastListUrl;
    if (s.slice(-1) == '/') s = s.slice(0,-1);
    var b = s.split('/');
    if (b.length >= 2) {
      b.pop();
      s = b.join('/');
      sNewUrl = s || '/';
    }
    else sNewUrl = '/';
    
    updateInputJson(sNewUrl, function(succ) {
      if (succ) sLastListUrl = sNewUrl;
    });
  }
}

function sublevelOnDbClick(event) {
  event.stopPropagation();
  
  if (sWorkDirUrl && sLastListUrl) {
    var targ = event.target, node = null;
    while (targ) {
      if (targ === document.body) break;
      if (targ.nodeName == 'TR') {
        node = targ;
        break;
      }
      targ = targ.parentNode;
    }
    
    var sNewUrl, sName = node && node.getAttribute('data-name');
    if (!sName) return;
    
    if (sLastListUrl.slice(-1) == '/')
      sNewUrl = sLastListUrl + sName;
    else sNewUrl = sLastListUrl + '/' + sName;
    updateInputJson(sNewUrl, function(succ) {
      if (succ) sLastListUrl = sNewUrl;
    });
  }
}

function goUpOnClick(event) {
  event.stopPropagation();
  
  var targ = event.target, node = null;
  while (targ) {
    if (targ.nodeName == 'TR') {
      node = targ;
      break;
    }
    targ = targ.parentNode;
  }
  if (!node || node.id !== 'goto-uplevel') return;
  
  hideAllFloatBtn();
    
  if (canShowUpldBtn && braObj) {
    var rect = node.getBoundingClientRect();
    newFolderNode.style.top = (rect.top - 1) + 'px';
    newFolderNode.style.display = 'block';
  }
}

function fileOnClick(event) {
  event.stopPropagation();
  
  var targ = event.target, node = null;
  while (targ) {
    if (targ.nodeName == 'TR') {
      node = targ;
      break;
    }
    targ = targ.parentNode;
  }
  if (!node) return;
  
  var sName = node.getAttribute('data-name');
  if (!sName) return;
  
  hideAllFloatBtn();
  
  var showMdBtn = false, img = null;
  var sMeta = node.getAttribute('data-type') || '';
  var sUrl = inputJson.path? inputJson.path + '/' + sName: sName;
  var rect = node.getBoundingClientRect();
  if (sMeta == 'text/x-markdown') {
    viewMdFileNode.style.top = (rect.top - 1) + 'px';
    viewMdFileNode.style.display = 'block';
    viewMdFileNode.setAttribute('mdsrc',sUrl);
    showMdBtn = true;
  }
  else if (sMeta.indexOf('image/') == 0) {
    var sDataUrl = getCacheImg(sUrl);
    var sUrl2 = sDataUrl? sDataUrl: sUrl;
    
    rect = node.getBoundingClientRect();
    img = previewImgNode.querySelector('img');
    if (img.getAttribute('src') === sUrl2 && img.complete)
      imgOnLoad();
    else {
      img.onload = imgOnLoad;
      img.setAttribute('title',sName);
      img.setAttribute('src',sUrl2);
      img.setAttribute('data-name',sName);
      img.setAttribute('data-type',sMeta);
    }
  }
  
  if (canShowUpldBtn && braObj && sUrl.indexOf('/'+braObj.repoName+'/') == 0) {
    var repoPath = sUrl.slice(braObj.repoName.length+2);
    if (repoPath.split('/').length > 1) {
      var rightWd = 8, sSha = node.getAttribute('data-sha') || '';
      if (showMdBtn) rightWd += (viewMdFileNode.clientWidth || 0);
      removFileNode.style.top = (rect.top - 1) + 'px';
      removFileNode.style.right = rightWd + 'px';
      removFileNode.style.display = 'block';
      removFileNode.setAttribute('rmvsrc',repoPath);
      removFileNode.setAttribute('data-sha',sSha);
    } // else, can not remove file that direct under repo
  }
  
  function imgOnLoad(event) {
    var wd = Math.min(320,document.body.clientWidth - 80), hi = img.naturalHeight / img.naturalWidth * wd;
    previewImgNode.style.top   = Math.floor(rect.top + rect.height/2 - hi/2) + 'px';
    previewImgNode.style.left  = (document.body.clientWidth - wd + 2) + 'px';
    previewImgNode.style.width = wd + 'px';
    previewImgNode.style.display = 'block';
  }
}

var currDragNode_ = null;

function fileDragStart(event) {
  if (!inputJson) return;
  
  var targ = event.target;
  while (targ) {
    if (targ === document.body) return;
    if (targ.nodeName == 'TR')
      break;
    targ = targ.parentNode;
  }
  if (!targ) return;
  
  var sName = targ.getAttribute('data-name'), sMeta = targ.getAttribute('data-type');
  if (!sName || !sMeta) return;
  var sUrl = inputJson.path || '';
  if (sUrl && sUrl.slice(-1) != '/')
    sUrl += '/' + sName;
  else sUrl += sName;
  sUrl = location__(sUrl).href;
  
  currDragNode_ = targ;
  event.dataTransfer.setData('text/plain',sUrl);
  event.dataTransfer.setData('text/uri-list',sUrl);
  if (sMeta.indexOf('image/') == 0) {
    var opt = {dragType:'image', dataType:sMeta, dragUrl:sUrl};
    event.dataTransfer.setData('application/json',JSON.stringify(opt));
  }
  var imgNode = targ.querySelector('img');
  if (imgNode)
    event.dataTransfer.setDragImage(imgNode,0,0);
}

function fileDragEnd(event) {
  currDragNode_ = null;
  if (window.parent && window.parent.window !== window) {
    var s = '[PROJECT_NAME]' + JSON.stringify({method:'dragEnd',param:['file']});
    window.parent.window.postMessage(s,'*');
  }
}

function thumbDragStart(event) {  // for template image node
  var targ = event.target, isJsonSvg = true;
  if (targ.nodeName == 'IMG')
    isJsonSvg = false;
  else {
    while (targ) {
      if (targ === document.body) return;
      if (targ.nodeName == 'DIV' && targ.classList.contains('thumb-item'))
        break;
      targ = targ.parentNode;
    }
  }
  if (!targ) return;
  
  var sUrl = targ.getAttribute(isJsonSvg?'data-src':'src') || '';
  if (!sUrl) return;
  
  currDragNode_ = targ;
  var opt = {dragType:'template', dragUrl:sUrl};
  if (isJsonSvg) opt.option = targ.wdgtJson || {};
  event.dataTransfer.setData('text/plain',sUrl);
  event.dataTransfer.setData('application/json',JSON.stringify(opt));
  event.dataTransfer.setDragImage(targ,0,0);
}

function thumbDragEnd(event) {
  currDragNode_ = null;
  if (window.parent && window.parent.window !== window) {
    var s = '[PROJECT_NAME]' + JSON.stringify({method:'dragEnd',param:['template']});
    window.parent.window.postMessage(s,'*');
  }
}

var re_abs_url_ = /^\/|http:|https:/;

window.addEventListener('load', function(event) {
  var param = getUrlParam(window.location.search.slice(1));
  var sPrjBase = decodeURIComponent(param.base || '');
  if (sPrjBase && sPrjBase.slice(-1) == '/') sPrjBase = sPrjBase.slice(0,-1);
  proxyDirList = !!param.repo;
  canShowHomeBtn = !!param.home;  // home=1
  canShowUpldBtn = !!(param.upload && param.repo);
  
  if (proxyDirList && utils && utils.gitOf) {
    var repoName = decodeURIComponent(param.repo);
    var siteHost  = window.location.hostname, sitePort = window.location.port;
    if (param.site) siteHost = decodeURIComponent(param.site); // param.site = 'api.github.com'
    var sHostPort = sitePort? siteHost + ':' + sitePort: siteHost;
    Git = (siteHost == 'localhost' || siteHost == '127.0.0.1')
        ? utils.gitOf(sHostPort,'http')   // fixed to http
        : utils.gitOf(sHostPort,'https'); // fixed to https, location.port should be ''
    
    userObj = new Git.User(param.user?decodeURIComponent(param.user):'pinp');
    if (!userObj.isLocal && param.token)
      Git.siteAuth = 'OAuth ' + decodeURIComponent(param.token);
    braObj = new Git.Branch(userObj,repoName,'gh-pages');
  }
  
  var sUrl = decodeURIComponent(param.url || ''), needJump = false;
  if (!sUrl) {
    if (sPrjBase)
      sUrl = sPrjBase; // default list resouce of current project
    else sUrl = 'templates';
  }
  else {
    if (sPrjBase && sUrl.search(re_abs_url_) != 0)
      sUrl = sPrjBase + '/' + sUrl;
    
    if (sUrl.slice(-5) == '.html') {
      setTimeout( function() {
        window.open(sUrl+(param.base?'?base='+param.base:''),'_self');
      },0);
      return;
    }
  }
  if (canShowHomeBtn) sWorkDirHome = sUrl;
  
  fileTBodyNode  = document.querySelector('#file-list tbody');
  uplevelTrNode  = document.querySelector('#goto-uplevel');
  widgetListNode = document.querySelector('#widget-list');
  previewImgNode = document.querySelector('#preview-img');
  removFileNode  = document.querySelector('#rmv-file');
  viewMdFileNode = document.querySelector('#open-md');
  newFolderNode  = document.querySelector('#new-folder');
  
  // define preview image dragging event
  var previewImg_ = previewImgNode.querySelector('img');
  previewImg_.ondragstart = function(event) {
    if (!inputJson) return;
    
    var targ = event.target, sUrl = '';
    if (targ.nodeName == 'IMG') {
      var sName = targ.getAttribute('data-name'), sMeta = targ.getAttribute('data-type');
      if (sName && sMeta) {
        sUrl = inputJson.path || '';
        if (sUrl && sUrl.slice(-1) != '/')
          sUrl += '/' + sName;
        else sUrl += sName;
        sUrl = location__(sUrl).href;
      }
    }
    if (!sUrl) return;
    
    currDragNode_ = targ;
    var opt = {dragType:'image', dataType:sMeta, dragUrl:sUrl};
    opt.clientWidth = targ.naturalWidth || 0;
    opt.clientHeight = targ.naturalHeight || 0;
    event.dataTransfer.setData('text/plain',sUrl);
    event.dataTransfer.setData('text/uri-list',sUrl);
    event.dataTransfer.setData('application/json',JSON.stringify(opt));
    event.dataTransfer.setDragImage(targ,0,0);
  };
  previewImg_.ondragend = function(event) {
    currDragNode_ = null;
    if (window.parent && window.parent.window !== window) {
      var s = '[PROJECT_NAME]' + JSON.stringify({method:'dragEnd',param:['image']});
      window.parent.window.postMessage(s,'*');
    }
  };
  
  removFileNode.addEventListener('click',removeFileClick,false);
  viewMdFileNode.addEventListener('click', function(event) {
    var targ = event.target;
    if (!targ || targ.parentNode !== viewMdFileNode) return;
    event.stopPropagation();
    
    var sUrl = viewMdFileNode.getAttribute('mdsrc') || '';
    if (sUrl) window.open('show_md.html?url='+encodeURIComponent(sUrl),'_blank');
  },false);
  newFolderNode.addEventListener('click', function(event) {
    event.stopPropagation();
    tryCreateFolder();
  },false);
  
  // initial config
  var b = document.querySelectorAll('#filelist-title th');
  if (b.length >= 2) {
    b[0].addEventListener('click',refreshOnClick,false);
    titleTdNode = b[1];
    
    var b2 = titleTdNode.querySelectorAll('img');
    homeImgNode = b2[0]; uploadImgNode = b2[1];
    homeImgNode.addEventListener('click',goHomeOnClick,false);
    uploadFileNode = titleTdNode.querySelector('input');
    uploadFileNode.onmouseover = function(ev) {uploadImgNode.style.borderColor='#fff #aaa #aaa #fff'};
    uploadFileNode.onmouseout = function(ev) {uploadImgNode.style.borderColor='transparent'};
    uploadFileNode.addEventListener('change',uploadOnSelect,false);
    titleSpanNode = titleTdNode.querySelector('span');
  }
  if (canShowUpldBtn && braObj)
    uplevelTrNode.addEventListener('click',goUpOnClick,false);
  uplevelTrNode.addEventListener('dblclick',uplevelOnDbClick,false);
  previewImgNode.addEventListener('click', function(event) {
    event.stopPropagation();
  },false);
  document.addEventListener('click',hideAllFloatBtn,false);
  
  hasProjBase = !!sPrjBase;
  sWorkDirUrl = sPrjBase? sPrjBase + '/$list': '/files/$list';
  sWorkDirBase = sPrjBase || '';
  sLastListUrl = sUrl;
  updateInputJson(sLastListUrl,function(succ){});
},false);

})();
</script>

</body>
</html>
